package org.strieber.fca;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.TreeSet;

public class KevinSort {
	
	String determinedAttributes = new String();
	List<String> input = new ArrayList<String>();
	List<String> attributes = new ArrayList<String>();
	ArrayList<ArrayList<TreeSet<String>>> rules = new ArrayList<ArrayList<TreeSet<String>>>();
	ArrayList<ArrayList<TreeSet<String>>> tempNewRules = new ArrayList<ArrayList<TreeSet<String>>>();
	
	public static void main (String[] args) {

		System.out.println("CAT2");
		KevinSort ks = new KevinSort();
		ks.runCAT2();
		ks.printData();
		ks.printData2();
		
		
		System.out.println("CRT2");
		ks = new KevinSort();
		ks.runCRT2();
		ks.printData();
		ks.printData2();
		
		System.out.println("CRT3");
		ks = new KevinSort();
		ks.runCRT3();
		ks.printData();
		ks.printData2();
		
		System.out.println("MDA4");
		ks = new KevinSort();
		ks.runMDA4();
		ks.printData();
		ks.printData2();
		
//		KevinSort ks = new KevinSort();
//		ks.test();
//		ks.printData();
//		Substitution sb = new Substitution(ks.getData());
//		
//		sb.appendPossibleValue("A", "1");
//		sb.appendPossibleValue("A", "2");
//		sb.appendPossibleValue("A", "3");
//		
//		sb.appendPossibleValue("B", "1");
//		sb.appendPossibleValue("B", "2");
//		sb.appendPossibleValue("B", "3");
//		
//		sb.appendPossibleValue("C", "1");
//		sb.appendPossibleValue("C", "2");
//		sb.appendPossibleValue("C", "3");
//		sb.appendPossibleValue("C", "4");
//		
//		sb.substitute();
//		System.out.println("after substitution: ");
//		System.out.println(sb.getRules());
	}
	
	public KevinSort() {
		
	}
	
	public KevinSort(List<String> input) {
		this.input = input;
		popRules();
	}
	
	public List<String> run(int iterations) {
		List<String> returnList = new ArrayList<String>();
		
		for (int i = 0; i < iterations; i++) {	
			/* System.out.println("before: ");
			printData(rules);
			*/ 
			makePass();
			rules.addAll(tempNewRules);
			/*
			System.out.println("after: ");
			printData(rules);
			*/
		}
		return returnList;
	}
	
	public void runCRT2() {
		popCRTValues2();
		popRules();
		
		for (int i = 0; i < 3; i++) {	
			makePass();
			rules.addAll(tempNewRules);
		}
	}
	
	
	public void runCRT3() {
		popCRTValues3();
		popRules();
		
		for (int i = 0; i < 3; i++) {	
			makePass();
			rules.addAll(tempNewRules);
		}
	}
	
	public void runCAT2() {
		popCATValues2();
		popRules();
		
		for (int i = 0; i < 3; i++) {	
			makePass();
			rules.addAll(tempNewRules);
		}
	}
	
	public void runMDA4() {
		popMDAValues4();
		popRules();
		
		for (int i = 0; i < 3; i++) {	
			makePass();
			rules.addAll(tempNewRules);
		}
	}
	
	public void test() {
		popTestData();
		popRules();

		for (int i = 0; i < 3; i++) {	
			/*
			System.out.println("before: ");
			printData(rules);
			*/
			makePass();
			rules.addAll(tempNewRules);
			/*
			System.out.println("after: ");
			printData(rules)
			*/;
		}
		//printData();
	}
	
	public void makePass() {

		tempNewRules.clear();
		ArrayList<ArrayList<TreeSet<String>>> tempRules;

		if (rules.size() > 0) {
			// exclude
			for (int e=0; rules.size() > 0 && e < rules.get(0).size(); e++) {
				// System.out.println("e " + e);

				for (int i=0; i < rules.size(); i++) {
					tempRules=new ArrayList<ArrayList<TreeSet<String>>>();

					for (int j = 0; j < rules.size(); j++) {
						if (i == j) {
							continue;
						}
						// System.out.println("i: "+ i +" j: " + j);
						// comparing treesets
						kloop:
							for (int k=0; k < rules.get(i).size(); k++) {

								if(e!=k && !rules.get(j).get(k)
										.equals(rules.get(i).get(k))) {
									/* System.out.println("breaking k: " + k); */
									break kloop;
								}
								if (k == rules.get(j).size() - 1) {
									/* System.out.println("adding to temp: " + rules.get(j)); */
									tempRules.add(rules.get(j));
									rules.remove(j);
									j--;
								}
							}
					} // end of j

					if (tempRules.size() > 0) {
						tempRules.add(rules.get(i));
						/* System.out.println("entered: tempRules"); */
						/* this.printData(tempRules); */
						rules.remove(i);
						i--;
						// combine possible var values in tempRules
						for (int m = 0; m < tempRules.size(); m++) {
							for (int p = 0; p < tempRules.get(m).size(); p++) {
								tempRules.get(0).get(p).addAll(tempRules.get(m).get(p));
							}
						}
						// add combined rules back to rules
						tempNewRules.add(tempRules.get(0));
					}
				} // end of i
			} // end of e
		}
	}


	public void popRules() {
		
		determinedAttributes = input.get(0).split("=>")[1].trim();
		
		for (int i = 0; i < input.size(); i++) {
			rules.add(new ArrayList<TreeSet<String>>());
			String raw = input.get(i).split("=>")[0].trim();
			String in = raw.substring(1, raw.length() - 1);
			String stringArray[] = in.split(", ");
			
			for (int j = 0; j < stringArray.length; j++) {
				rules.get(i).add(new TreeSet<String>());
				String attribute = stringArray[j].split("=")[0];
				/* System.out.println("attribute: " + attribute); */
				String valueString = stringArray[j].split("=")[1].split(" ")[0];
				attributes.add(attribute);
				rules.get(i).get(j).add(valueString);
			}		
		}
	}

	public void printData2(){
		System.out.println("printing rules:");
		for(ArrayList<TreeSet<String>> rule:rules){
			System.out.println(rule);
		}
		System.out.println("");
	}
	
	
	public String getData() {
		StringBuilder sb = new StringBuilder();
		for (ArrayList<TreeSet<String>> rule : rules) {
			for (int i = 0; i < rule.size(); i++) {
				// print all the rules nicely
				Iterator<String> it = rule.get(i).iterator();
				
				while (it.hasNext()) {
					sb.append(attributes.get(i) + " = " + it.next() + " OR ");
				}
				
				sb.delete(sb.length() - 4, sb.length() - 1);
				sb.append("AND ");
			}
			sb.delete(sb.length() - 4, sb.length() - 1);
		}
		String result = "[ " + sb.toString() + "] => " + determinedAttributes;
		return result;
	}
	
	public String getData2() {
		StringBuilder sb = new StringBuilder();
		for (ArrayList<TreeSet<String>> rule : rules) {
			for (int i = 0; i < rule.size(); i++) {
				// print all the rules nicely
				Iterator<String> it = rule.get(i).iterator();
				
				while (it.hasNext()) {
					sb.append(attributes.get(i) + " = " + it.next() + " OR ");
				}
				sb.append("AND ");
			}
		}
		String result = "[ " + sb.toString() + "] => " + determinedAttributes;
		return result;
	}
	
	
	
	public void printData() {
		System.out.println("printing rules:");
		System.out.println(getData());
	}

	
	public void popCATValues2() {
		input.add("[FUME=Y, YEF=0] => [CAT=2]");
		input.add("[MF=YES, YEF=0] => [CAT=2]");
		input.add("NOISE=YES, YEF=0] => [CAT=2]");
		input.add("[SYST=1, YEF=0] => [CAT=2]");
		input.add("[A=1, Y=0] => [CAT=2]");
		input.add("[A=1, Y=2] => [CAT=2]");
	}
	
	public void popCRTValues2() {
		input.add("[FUME=Y, HGHT=0]	=>	[CRT=2]");
		input.add("[HGHT=0, MF=YES]	=>	[CRT=2]");
		input.add("[DIST=0, HGHT=0]	=>	[CRT=2]");
	}
	
	public void popCRTValues3() {
		input.add("[HGHT=0, RAD=Y, SYST=1]	=>	[CRT=2]");
		input.add("[HGHT=0, MF=YES, RAD=Y]	=>	[CRT=2]");
		input.add("[HGHT=0, MF=YES, SYST=1]	=>	[CRT=2]");
		input.add("[BBP=Y, HGHT=0, NOISE=Y]	=>	[CRT=2]");
		input.add("[FUME=Y, HGHT=0, RAD=Y]	=>	[CRT=2]");
		input.add("[HGHT=0, NOISE=Y, RAD=Y]	=>	[CRT=2]");
		input.add("[BBP=Y, HGHT=0, SYST=1]	=>	[CRT=2]");
		input.add("[FUME=Y, HGHT=0, SYST=1]	=>	[CRT=2]");
	}
	
	public void popMDAValues4() {
		input.add("[BBP=Y, DIST=1, SYST=1, WGHT=0]	=>	[MDA=2]");
		input.add("[DIST=1, FUME=Y, SYST=1, WGHT=0]	=>	[MDA=2]");
		input.add("[DIST=1, RAD=Y, SYST=1, WGHT=0]	=>	[MDA=2]");
	}
	
	public void popTestData() {
		input.add("[A=1, B=2, C=1] => [D=1]");
		input.add("[A=2, B=2, C=1] => [D=1]");
		input.add("[A=3, B=2, C=1] => [D=1]");

		input.add("[A=1, B=2, C=2] => [D=1]");
		input.add("[A=3, B=2, C=2] => [D=1]");
		input.add("[A=2, B=2, C=2] => [D=1]");
		
		input.add("[A=3, B=3, C=1] => [D=1]");
		input.add("[A=2, B=3, C=1] => [D=1]");
		input.add("[A=1, B=3, C=1] => [D=1]");

		input.add("[A=3, B=3, C=2] => [D=1]");
		input.add("[A=2, B=3, C=2] => [D=1]");
		input.add("[A=1, B=3, C=2] => [D=1]");
	}
}